/**************************************************************************//**
* @file     spim spi.c
* @version  V1.00
*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "bsp.h"
#include "bsp_io.h"
#include "pincfg.h"
#include "swspi.h"
#include "nor_cmd.h"
#include "common.h"

uint8_t nor_id[8];

/*******************************************************************************
* @brief  gpio cfg
*******************************************************************************/
static gpio_init_cfg_type gpio_cfg[] = 
{
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_1},		//CLK
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_10},	//MOSI
    {GPIOB, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_11},		//MISO
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_7},		//WP
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_6},		//HOLD
    {GPIOA, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_8},		//CS
};

static gpio_init_cfg_type spi_p[] = 
{
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_10},	//MOSI
    {GPIOB, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz,  1, GPIO_Pins_11},	//MISO
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_7},		//WP
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_6},		//HOLD
};

static gpio_init_cfg_type qpi_o_p[] = 
{
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_10},	//MOSI
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_11},	//MISO
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_7},		//WP
    {GPIOB, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_6},		//HOLD
};

static gpio_init_cfg_type qpi_i_p[] = 
{
    {GPIOB, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_10},		//MOSI
    {GPIOB, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_11},		//MISO
    {GPIOB, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_7},		//WP
    {GPIOB, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_6},		//HOLD
};

/*******************************************************************************
* @brief  spi io
*******************************************************************************/
#define cs        PAout(8)
#define sck       PBout(1)
#define mosi      PBout(10)
#define miso      PBin(11)
#define hold      PBout(6)
#define wp        PBout(7)

/*******************************************************************************
* @brief  qpi io
*******************************************************************************/
#define qi0      PBin(10)
#define qi1      PBin(11)
#define qi2      PBin(7)
#define qi3      PBin(6)

#define qo0      PBout(10)
#define qo1      PBout(11)
#define qo2      PBout(7)
#define qo3      PBout(6)

/*******************************************************************************
* @brief  spi io ctr
*******************************************************************************/
static void cs_out_high(void)
{
	cs = 1;
}

static void cs_out_low(void)
{
	cs = 0;
}

static void sck_out_high(void)
{
	sck = 1;
}

static void sck_out_low(void)
{
	sck = 0;
}

static void mosi_out_high(void)
{
	mosi = 1;
}
static void mosi_out_low(void)
{
	mosi = 0;
}

static uint8_t miso_st_get(void)
{
    __DSB();
	return miso;
}

static void insert_clks(void)
{
	__DSB();
}
static void io_out(uu32 qio)
{
	if(qio & 1) qo0 = 1; else qo0 = 0;
	if(qio & 2) qo1 = 1; else qo1 = 0;
	if(qio & 4) qo2 = 1; else qo2 = 0;
	if(qio & 8) qo3 = 1; else qo3 = 0;
}

static uu32 io_in(void)
{
	uint32_t rd = 0;
	
	if(qi0) rd |= 1;
	if(qi1) rd |= 2;
	if(qi2) rd |= 4;
	if(qi3) rd |= 8;
	
	return rd;
}

/*******************************************************************************
* @brief  spi config
*******************************************************************************/
static spi_info_type spim_spi_info;

static spi_cfg_type spi_cfg =
{
	.cs_out_high = cs_out_high,
	.cs_out_low = cs_out_low,
	.sck_out_high = sck_out_high,
	.sck_out_low = sck_out_low,
	.mosi_out_high = mosi_out_high,
	.mosi_out_low = mosi_out_low,
	.miso_st_get = miso_st_get,
	.insert_clks = insert_clks,
	.info = &spim_spi_info,
};

static qpi_cfg_type qpi_cfg =
{
	.cs_out = 0,
	.io_in = io_in,
	.io_out = io_out,
	.sck_out_high = sck_out_high,
	.sck_out_low = sck_out_low,
};

/*******************************************************************************
* @brief  spim_sw_spi_init
* \param[in] none
* \retval: none
*******************************************************************************/
void spim_sw_spi_init(void)
{
	bsp_gpio_mode(gpio_cfg, 6);
	
    PBout(7) = 1;
    PBout(6) = 1;
    
    sw_spi_speed(&spi_cfg, 1);
    spim_spi_info.bits = 7;
	
	nor_cmd_signal_exe(SPI_NOR_CMD_Enable_Reset);
	nor_cmd_signal_exe(SPI_NOR_CMD_Reset);
	
	//nor_init(1);
	
    nor_id_read(nor_id);
	
	nor_read(0x800000, 8, nor_id);
}

/*******************************************************************************
* @brief  nor_spi_cs
* \param[in] st
* \retval: none
*******************************************************************************/
void nor_spi_cs(uint8_t st)
{
    sw_spi_cs(&spi_cfg, st);
}

void nor_spi_mode(nor_spi_type mode)
{
    switch(mode)
	{
		case SPI_NOR_QPI_READ_MODE:
			bsp_gpio_mode(qpi_i_p, 4);
			break;
		case SPI_NOR_QPI_WRITE_MODE:
			bsp_gpio_mode(qpi_o_p, 4);
			break;
		default:
			bsp_gpio_mode(spi_p, 4);
			break;
	}
}

uint8_t nor_spi_rw(uint8_t dataW)
{
    return sw_spi8_rw(&spi_cfg, dataW);
}

uint8_t nor_spi_cmd_send(uint8_t *dataw, uint8_t Len)
{
    while(Len--)
    {
        sw_spi8_rw(&spi_cfg, *dataw++);
    }
	return 0;
}

uint8_t nor_spi_write(uint8_t *dataw, uint32_t Len)
{
	sw_spi32_write(&spi_cfg, (uu32 *)dataw, Len>>2);
	
	/*
    while(Len--)
    {
        sw_spi_rw(&spi_cfg, *dataw++);
    } */
	return 0;
}

uint8_t nor_spi_read(uint8_t *datar, uint32_t Len)
{
	sw_spi32_read(&spi_cfg, (uu32 *)datar, Len>>2);
	
	/*
    while(Len--)
    {
        *datar = sw_spi_rw(&spi_cfg, 0);
        datar++;
    } */
	return 0;
}

uint8_t nor_qpi_cmd_send(uint8_t *dataw, uint32_t Len)
{
    sw_qpi8_write(&qpi_cfg, dataw, Len);
	return 0;
}

uint8_t nor_qpi_write(uint8_t *dataw, uint32_t Len)
{
    sw_qpi32_write(&qpi_cfg, (uu32*)dataw, Len>>2);
	return 0;
}

uint8_t nor_qpi_read(uint8_t *datar, uint32_t Len)
{
    sw_qpi32_read(&qpi_cfg, (uu32*)datar, Len>>2);
	return 0;
}
